package main

import (
	"bufio"
	"bytes"
	"fmt"
	"os"
	"strings"
)

const KeyWordEnd string = "waiting for your expanding"

type WORD struct {
	//syn单词种别码
	typeNum int
	//单词或整形常数
	word string
}

//输入字符串
var input = ""

//单词缓冲区
var token [1000]byte
var tokenString string

//输入缓冲区指针
var pInput int

//单词缓冲区指针
var pToken int

//当前读入字符
var ch byte

//可扩充的关键字数组
var rwtab = [...]string{"begin", "if", "then", "while", "do", "end", KeyWordEnd}

func main() {
	fmt.Println("Enter Your words(end with #):")
	for {
		var i string
		end := "#"
		Scanf(&i)
		if strings.Contains(i, end) {
			//在#处截取字符串（包括#）
			rs := []rune(i)
			i = string(rs[0 : strings.Index(i, end)+1])
			//截取字符串结束
			input += i

			//循环结束
			break
		}
		input += i
	}
	pInput = 0
	fmt.Printf("Your words：\n%s\n", input)

	for {
		oneword := scaner()

		//遇到#结束
		if oneword.typeNum >= 1000 || oneword.typeNum == 0 {
			break
		}
		if oneword.typeNum < 1000 {
			fmt.Printf("(%d,%s)", oneword.typeNum, oneword.word)
		}
	}

	return
}

func Scanf(a *string) {
	reader := bufio.NewReader(os.Stdin)
	data, _, _ := reader.ReadLine()
	*a = string(data)
}

//从输入字符串中读取一个字符
func getch() byte {
	ch = input[pInput]
	pInput++
	return ch
}

//去掉空白符号
func getbc() {
	for ch == ' ' || ch == 10 {
		ch = input[pInput]
		pInput++
	}
}

//拼接单词
func concat() {
	var buff bytes.Buffer
	buff.WriteByte(ch)
	tokenString += buff.String()
}

//判断是否字母
func letter() int {
	if ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' {
		return 1
	} else {
		return 0
	}
}

//判断是否数字
func digit() int {
	if ch >= 48 && ch <= 57 {
		return 1
	} else {
		return 0
	}
}

//检索关键字表格
func reserve() int {
	for i := 0; strings.Compare(rwtab[i], KeyWordEnd) != 0; i++ {
		if strings.Compare(rwtab[i], tokenString) == 0 {
			return i + 1
		}
	}
	return 10
}

//回退一个字符
func retract() {
	pInput = pInput - 1
}

//词法扫描函数
func scaner() (myword WORD) {
	myword.typeNum = 10
	myword.word = ""
	tokenString = ""
	getch()
	getbc()
	if letter() == 1 {
		for letter() == 1 || digit() == 1 {
			concat()
			getch()
		}
		retract()
		myword.typeNum = reserve()
		myword.word = tokenString
		return myword
	} else if digit() == 1 {
		for digit() == 1 {
			concat()
			getch()
		}
		retract()
		myword.typeNum = 20
		myword.word = tokenString
		return myword
	} else {
		switch ch {
		case '+':
			myword.typeNum = 13
			myword.word = "+"
			return myword
		case '-':
			myword.typeNum = 14
			myword.word = "-"
		case '*':
			myword.typeNum = 15
			myword.word = "*"
		case '/':
			myword.typeNum = 16
			myword.word = "/"
		case '(':
			myword.typeNum = 27
			myword.word = "("
		case ')':
			myword.typeNum = 28
			myword.word = ")"
		case ':':
			getch()
			if ch == '=' {
				myword.typeNum = 18
				myword.word = ":="
				return myword
			}
			retract()
			myword.typeNum = 17
			myword.word = ":"
			return myword
		case ';':
			myword.typeNum = 26
			myword.word = ";"
			return myword
		case '<':
			getch()
			if ch == '>' {
				myword.typeNum = 21
				myword.word = "<>"
				return myword
			} else if ch == '=' {
				myword.typeNum = 22
				myword.word = "<="
				return myword
			}
			retract()
			myword.typeNum = 20
			myword.word = ">"
			return myword
		case '>':
			getch()
			if ch == '=' {
				myword.typeNum = 24
				myword.word = ">="
				return myword
			}
			retract()
			myword.typeNum = 23
			myword.word = "<"
			return myword
		case '=':
			myword.typeNum = 25
			myword.word = "="
		case '#':
			myword.typeNum = 0
			myword.word = "#"
		default:
			myword.typeNum = -1
			myword.word = "ERROR"
			return myword
		}
	}
	return myword
}

//begin x:= 9; if x>0 then x:=2*x+1/3;end #
